#include <cstdio>

#include <BWAPI.h>
#include <BWAPI/Client.h>
#include <iostream>
#include <windows.h>

#include <string>
#include "controlBot.h"

using namespace BWAPI;

clock_t _lastTime;
float _maxBattleDuration = 120000;
//float _maxBattleDuration = -1;

float diffclockI(clock_t clock1, clock_t clock2)
{
	float diffticks=clock2-clock1;
	float diffms=(diffticks*1000)/CLOCKS_PER_SEC;
	return diffms;
}

list<string> ParseCsvString(string csv)
{
	list<string> items;

	while (csv.find(",", 0) != string::npos)
	{
		size_t  pos = csv.find(",", 0);
		string temp = csv.substr(0, pos);
		csv.erase(0, pos + 1);
		items.push_back(temp);
	}

	return items;
}

void reconnect()
{
	while(!BWAPIClient.connect())
	{
		Sleep(1000);
	}
}

int main(int argc, const char* argv[])
{
	//srand(time(NULL));
	int i = 1;

	if(argc < 5)
	{
		cout << "USEAGE [policy mode (single)] [policy files path] [fileExtension] [time step duration] [action prefix] <output results file> <timeout ms>" << endl;
		cout << "USEAGE [policy mode (multi)] [policy folders csv] [fileExtension] [time step duration] [action prefix] <output results file> <seed> <timeout ms>" << endl;
		cout << "USEAGE [policy mode (multireplay)] [policy folders csv] [fileExtension] [time step duration] [action prefix] <output results file>" << endl;
		std::cout << "Press ENTER to continue..." << std::endl;
		std::cin.ignore();
		return 0;
	}

	string policyMode = argv[1];
	PolicyFileParser * parser;
	vector<PolicyFileParser*> parsers;

	string policyFilePath = argv[2];
	string fileExtension = argv[3];
	string resultsFile = "";
	int timeStepDuration = atoi(argv[4]);
	string actionPrefix = argv[5];

	int numBattles = 0;

	if (argc >= 7)
	{
		resultsFile = argv[6];
	}

	if (argc >= 8)
	{
		numBattles = atoi(argv[7]);
		cout << "End After " << numBattles << " battles" << endl;
	}

	int seed = 1;
	if (argc >=9)
	{
		seed = atoi(argv[8]);
		cout << "Manual Seed " << seed << endl;
	}
	else
	{
		time_t timeVal=0;
		time(&timeVal);
		int seed = (unsigned int)timeVal;
		cout << "Auto Seed " << seed << endl;
	}

	srand(seed);

	if(policyMode == "single")
	{
		parser = new PolicyFileParser(policyFilePath , fileExtension, true, actionPrefix);
	}
	else if (policyMode == "multi")
	{
		_maxBattleDuration = 130000;
		list<string> folders = ParseCsvString(policyFilePath);

		for(list<string>::iterator it = folders.begin(); it != folders.end(); it++)
		{
			PolicyFileParser * tempFileParser = new PolicyFileParser(*it, fileExtension, true, actionPrefix);
			parsers.push_back(tempFileParser);
		}
	}
	else if (policyMode == "multireplay")//This is the mode for simulating replay policies, because they are incomplete, combines into one super policy
	{
		parser = new PolicyFileParser(fileExtension, true, actionPrefix);
		list<string> folders = ParseCsvString(policyFilePath);

		for(list<string>::iterator it = folders.begin(); it != folders.end(); it++)
		{
			string folder = *it;
			parser->ChangeDirectory(folder);
			parser->PreloadedFiles();
		}
	}
	else
	{
		cout << "USEAGE [policy mode (single)] [policy files path] [fileExtension] [time step duration] [action prefix] <output results file>" << endl;
		cout << "USEAGE [policy mode (multi)] [policy folders csv] [fileExtension] [time step duration] [action prefix] <output results file>" << endl;
		cout << "USEAGE [policy mode (multireplay)] [policy folders csv] [fileExtension] [time step duration] [action prefix] <output results file>" << endl;
		std::cout << "Press ENTER to continue...2" << std::endl;
		std::cin.ignore();
		return 0;
	}
	
	std::cout << "Connecting..." << std::endl;

	reconnect();
	while(true)
	{			
		std::cout << "waiting to enter match" << std::endl;

		if(numBattles > 0)
		{
			if(i > numBattles)
			{
				exit(0);
			}
		}

		while ( !Broodwar->isInGame() )
		{
			BWAPI::BWAPIClient.update();
			if (!BWAPI::BWAPIClient.isConnected())
			{
				std::cout << "Reconnecting..." << std::endl;;
				reconnect();
			}
		}
		std::cout << "starting match " << i << std::endl;
		i++;
		std::cout << "The map is " << Broodwar->mapName() << ", a " << Broodwar->getStartLocations().size() << " player map" << std::endl;
		// Enable some cheat flags

		Broodwar->enableFlag(Flag::UserInput);

		//if multiple policies then choose a random one
		if (policyMode == "multi")
		{
			int rModel = rand() % parsers.size();
			parser = parsers[rModel];
		}

		ControlBot bot(parser, parser->GetNumerOfTimeSteps(), timeStepDuration, resultsFile);

		bool resigned = false;
		bool alive = true;

		_lastTime = clock();
		float countdown = _maxBattleDuration;

		while(Broodwar->isInGame())
		{
			if(countdown < 0)
			{
				cout << "Game Timeout, Surrendering" << endl;
				Broodwar->leaveGame();
				resigned = true;
			}

			bot.Tick();
			alive = bot.IsAlive();

			Broodwar->drawText(CoordinateType::Screen, 0,0, parser->GetCurrDirectory().c_str());
			BWAPI::BWAPIClient.update();

			if (!BWAPI::BWAPIClient.isConnected())
			{
				std::cout << "Reconnecting..." << std::endl;
				reconnect();
			}

			countdown -= diffclockI(_lastTime, clock());
			_lastTime = clock();		
			
		}

		std::cout << "Game ended" << std::endl;

		if (resigned)
		{
			std::cout << "Draw" << std::endl;
			bot.LogResult("Draw");
		}
		else if (alive && !resigned)
		{
			std::cout << "Won" << std::endl;
			bot.LogResult("Win");
		}
		else if (!alive)
		{
			std::cout << "Loose" << std::endl;
			bot.LogResult("Loose");
		}
		
	}
	std::cout << "Press ENTER to continue..." << std::endl;
	std::cin.ignore();
	return 0;
}
